package com.aliyun.iot.demo.iothub;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

import com.aliyun.iot.util.SignUtil;

public class Test {

    //1,配置参数
    /** 从控制台获取productKey、deviceName、deviceSecret信息*/
    private static String productKey = "a1NcRC0sKf8";
    private static String deviceName = "dev_1";
    private static String deviceSecret = "";
    /** 用于测试的topic */
    private static String subTopic = "/"+productKey+"/"+deviceName+"/get";
    private static String pubTopic = "/"+productKey+"/"+deviceName+"/pub";
	
	public static void main(String[] args) throws Exception {
	    //2,连接MQTT服务器
	     //客户端设备 自己的一个标记 建议是mac或sn ，不能为空，32字符内
	     String clientId = InetAddress.getLocalHost().getHostAddress();
	     //设备认证
		Map<String, String> params = new HashMap<String, String>();
	            params.put("productKey", productKey); //这个是对应用户在控制台注册的 设备productkey
	            params.put("deviceName", deviceName); //这个是对应用户在控制台注册的 设备name
	            params.put("clientId", clientId);
	            String t = System.currentTimeMillis()+"";
	            params.put("timestamp", t);
	            //mqtt服务器 ，tls的话ssl开头，tcp的话改成tcp开头
	            String targetServer = "ssl://"+productKey+".iot-as-mqtt.cn-shanghai.aliyuncs.com:1883";
	            //客户端ID格式:  
	            String mqttclientId = clientId + "|securemode=2,signmethod=hmacsha1,timestamp="+t+"|"; //设备端自定义的标记，字符范围[0-9][a-z][A-Z]
	            String mqttUsername = deviceName+"&"+productKey;//mqtt用户名格式
	            String mqttPassword = SignUtil.sign(params, deviceSecret, "hmacsha1");//签名
	            MemoryPersistence persistence = new MemoryPersistence();
	            //连接mqtt的代码片段
	            MqttClient sampleClient = new MqttClient(targetServer, mqttclientId, persistence);
	            MqttConnectOptions connOpts = new MqttConnectOptions();
	            connOpts.setMqttVersion(4);// MQTT 3.1.1
	            connOpts.setSocketFactory(createSSLSocket());
	            //设置是否自动重连
	            connOpts.setAutomaticReconnect(true);
	            //如果是true 那么清理所有离线消息，即qos1 或者 2的所有未接收内容
	            connOpts.setCleanSession(false);
	            connOpts.setUserName(mqttUsername);
	            connOpts.setPassword(mqttPassword.toCharArray());
	            connOpts.setKeepAliveInterval(80);//心跳时间 建议60s以上
	            sampleClient.connect(connOpts);
	            
	            //4,数据接收
	            //订阅某个topic，一旦有数据会回调到这里
	            sampleClient.subscribe(subTopic, new IMqttMessageListener() {
	                      @Override
	                      public void messageArrived(String topic, MqttMessage message) throws Exception {
	                          //设备订阅topic成功后，数据会回调这里
	                          //重复订阅无影响
	                    	  System.out.println("接收到消息,来至Topic [" + topic + "] , 内容是:["
	                                  + new String(message.getPayload(), "UTF-8") + "],  ");
	                      }
	                  });
	           
	            //3,数据发送
//	            String content = "要发送的数据内容, 这个内容可以是任意格式";
//	            MqttMessage message = new MqttMessage(content.getBytes("utf-8"));
//	            message.setQos(0);//消息qos 0:最多一次，1:至少一次
//	            sampleClient.publish(pubTopic, message);//发送数据到某个topic
	}
	
	  private static SSLSocketFactory createSSLSocket() throws Exception {
	        SSLContext context = SSLContext.getInstance("TLSV1.2");
	        context.init(null, new TrustManager[] {new ALiyunIotX509TrustManager()}, null);
	        SSLSocketFactory socketFactory = context.getSocketFactory();
	        return socketFactory;
	    }
}
